package com.ebase.core.config;

import com.ebase.core.support.Constants;
import com.ebase.core.support.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;

/**
 * Package Name:com.ebase.core.config
 * Description: That's the purpose of the file
 * Date:2016/7/28 11:41
 * Copyright (c) 2016, zhongmu@suneee.com All Rights Reserved.
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
    @Override
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            /** 重写生成key方法 */
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                StringBuilder sb = new StringBuilder(Constants.CACHE_NAMESPACE);
                CacheConfig cacheConfig = o.getClass().getAnnotation(CacheConfig.class);
                Cacheable cacheable = method.getAnnotation(Cacheable.class);//@Cacheable：负责将方法的返回值加入到缓存中
                CachePut cachePut = method.getAnnotation(CachePut.class);
                //@CachePut：这个注释可以确保方法被执行，同时方法的返回值也被记录到缓存中。
                //@Cacheable：当重复使用相同参数调用方法的时候，方法本身不会被调用执行，即方法本身被略过了，取而代之的是方法的结果直接从缓存中找到并返回了。

                CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);//@CacheEvict：负责清除缓存
                if (cacheable != null) {
                    String[] cacheNames = cacheable.value();
                    if (cacheNames != null && cacheNames.length > 0) {
                        sb.append(cacheNames[0]);
                    }
                } else if (cachePut != null) {
                    String[] cacheNames = cachePut.value();
                    if (cacheNames != null && cacheNames.length > 0) {
                        sb.append(cacheNames[0]);
                    }
                } else if (cacheEvict != null) {
                    String[] cacheNames = cacheEvict.value();
                    if (cacheNames != null && cacheNames.length > 0) {
                        sb.append(cacheNames[0]);
                    }
                }
                if (cacheConfig != null && sb.toString().equals(Constants.CACHE_NAMESPACE)) {
                    String[] cacheNames = cacheConfig.cacheNames();
                    if (cacheNames != null && cacheNames.length > 0) {
                        sb.append(cacheNames[0]);
                    }
                }
                if (sb.toString().equals(Constants.CACHE_NAMESPACE)) {
                    sb.append(o.getClass().getName());
                }
                if (objects != null) {
                    sb.append(":");
                    if (objects.length == 1) {
                        if (objects[0] instanceof Integer || objects[0] instanceof String) {
                            sb.append(objects[0]);
                        } else {
                            try {
                                sb.append(objects[0].getClass().getMethod("getId").invoke(objects[0]));
                            } catch (Exception e) {
                                throw new BusinessException("Not support.");
                            }
                        }
                    } else {
                        sb.append(StringUtils.join(objects, ","));
                    }
                }
                return sb.toString();
            }
        };
    }
}
